package com.slmn.buildin.money;

import java.math.BigDecimal;

/**
 * <p>
 *  An abstraction for a money value using as efficient as possible format to keep and process your data.
 *  All methods allocating a new Money object will try to output the most efficient prepresentation
 *  (for example, if precision=1, then 0.05+0.05 (each of them does not fit into precision) will be equal to
 *  0.1 (units=1, precision=1).
 * </p>
 * <p>
 *  You should use one of <code>to*</code> methods to convert it into a more commonly used formats after the
 *  calculation is over.
 * </p>
 */
public interface Money {

    /**
     * Convert to the original currency - divide <code>units</code> by <code>10^precision</code>.
     * @return <code>units / (10^precision)</code>
     */
    public double toDouble();

    /**
     * Convert into a String in a plain notation with a decimal dot.
     * @return a String in a plain notation with a decimal dot.
     */
    public String toString();

    /**
     * Convert this value into a BigDecimal. This method is also used for arithmetic calculations when necessary.
     * @return This object as BigDecimal
     */
    public BigDecimal toBigDecimal();

    /**
     * Add another Money object to this one.
     * @param other Other Money object
     * @return A new Money object normalized to the efficient representation if possible
     */
    public Money add( final Money other );

    /**
     * Return this value with an opposite sign.
     * @return A new object with the same value with a different sign
     */
    public Money negate();

    /**
     * Subtract another Money object from this one.
     * @param other Other money object
     * @return A new Money object normalized to the efficient representation if possible
     */
    public Money subtract( final Money other );

    /**
     * Multiply the current object by the <code>long</code> value.
     * @param multiplier Multiplier
     * @return A new Money object normalized to the efficient representation if possible
     */
    public Money multiply( final long multiplier );

    /**
     * Multiply the current object by the <code>double</code> value.
     * @param multiplier Multiplier
     * @return A new Money object normalized to the efficient representation if possible
     */
    public Money multiply( final double multiplier );

    /**
     * Divide the current object by the given <code>long</code> divider.
     * @param divider Divider
     * @param precision Maximal precision to keep. We will round the next digit.
     * @return A new Money object normalized to the efficient representation if possible
     */
    public Money divide( final long divider, final int precision );

    /**
     * Divide the current object by the given <code>long</code> divider.
     * @param divider Divider
     * @param precision Maximal precision to keep. We will round the next digit.
     * @return A new Money object normalized to the efficient representation if possible
     */
    public Money divide( final double divider, final int precision );

    /**
     * Truncate the current value leaving no more than {@code maximalPrecision} signs after decimal point.
     * The number will be rounded towards closest digit (0-4 -> 0; 5-9 -> 1)
     * @param maximalPrecision Required precision
     * @return A new Money object normalized to the efficient representation if possible
     */
    public Money truncate( final int maximalPrecision );
}